using System;
using System.Collections.Generic;
using System.Text;

namespace FE
{
    public class Map
    {
        public int Width
        {
            get { return width; }
        }
        public int Height
        {
            get { return height; }
        }
        private int width, height;
        private MapNode[][] nodes;
        public MapNode this[int x, int y]
        {            
            get
            {
                return nodes[x][y];
            }
        } 

        public Map (int width, int height)
        {
            this.width = width;
            this.height = height;
            nodes = new MapNode[width][];
            for (int i = 0; i < width; i++)
            {
                nodes[i] = new MapNode[height];
                for (int j = 0; j < height; j++)
                {
                    nodes[i][j] = new MapNode(this);
                }
            }
            for (int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    MapNode mn = nodes[i][j];
                    if (j == 0)
                    {
                        mn.N = null;
                        mn.S = nodes[i][j + 1];
                    } 
                    else if (j == height - 1)
                    {
                        mn.N = nodes[i][j - 1];
                        mn.S = null;
                    } 
                    else
                    {
                        mn.N = nodes[i][j - 1];
                        mn.S = nodes[i][j + 1];
                    }
                    if (i == 0)
                    {
                        mn.W = null;
                        mn.E = nodes[i + 1][j];
                    }
                    else if (i == width - 1)
                    {
                        mn.W = nodes[i - 1][j];
                        mn.E = null;
                    }
                    else
                    {
                        mn.W = nodes[i - 1][j];
                        mn.E = nodes[i + 1][j];
                    }
                }
            }
        }

        int currentPlayer = 0;
        public Player NextPlayer()
        {
            if (currentPlayer == PlayerOrder.Count) currentPlayer = 0;
            Player p = PlayerOrder[currentPlayer];
            currentPlayer ++;
            return p;
        }
        public List<Player> PlayerOrder = new List<Player>();
        public Player GetUnitOwner(UnitStatus unit)
        {
            foreach (Player p in PlayerOrder)
            {
                if (p.OwnsUnit(unit)) {
                    return p;
                }
            }
            return null;
        }
        public static Map CreateTestMap()
        {
            Map m = new Map(4, 3);

            Player one = new HumanPlayer();
            one.Name = "Poot";
            Player two = new ComputerPlayer();
            two.Name = "Enemy";

            m.PlayerOrder.Add(one);
            m.PlayerOrder.Add(two);

            m.nodes[0][0].tile = new PlainsTile();
            m.nodes[1][0].tile = new PlainsTile();
            m.nodes[2][0].tile = new PlainsTile();
            m.nodes[3][0].tile = new PlainsTile();

            m.nodes[0][1].tile = new MountainsTile();
            m.nodes[1][1].tile = new MountainsTile();
            m.nodes[2][1].tile = new MountainsTile();
            m.nodes[3][1].tile = new WoodsTile();

            m.nodes[0][2].tile = new PlainsTile();
            m.nodes[1][2].tile = new PlainsTile();
            m.nodes[2][2].tile = new PlainsTile();
            m.nodes[3][2].tile = new PlainsTile();

            Sebastien s = new Sebastien();
            TestMonster tm = new TestMonster();
            TestMonster tm2 = new TestMonster();
            tm.Name = "Monster One";
            tm2.Name = "Monster Two";
            m.nodes[0][0].unit = one.AddUnit(s);
            m.nodes[0][2].unit = two.AddUnit(tm);
            m.nodes[1][2].unit = two.AddUnit(tm2);

            return m;
        }
        public void ClearHighlights()
        {
            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    this[x, y].highlightAction = GameAdapter.Actions.Null;
                }
            }
        }
        public void RelocateUnit(int x0, int y0, int x1, int y1)
        {
            if (x0 == x1 && y0 == y1) return;
            Map.MapNode mn = this[x0, y0];
            UnitStatus u = mn.unit;
            Map.MapNode mn1 = this[x1, y1];
            mn1.unit = u;
            mn.unit = null;
        }

        public class MapNode
        {
            public MapNode(Map map)
            {
                this.map = map;
            }
            public Map map;
            public UnitStatus unit;
            public Tile tile;
            public MapNode N, S, E, W;
            public GameAdapter.Actions highlightAction;

            public List<MapNode> SearchAttack(int rangeMin, int rangeMax)
            {
                List<MapNode> nodes = new List<MapNode>();
                SearchAttack(this, rangeMin, rangeMin, 0, nodes);
                return nodes;
            }
            private void SearchAttack(MapNode current, int rangeMin, int rangeMax, int distance, List<MapNode> nodes)
            {
                if (current == null) return;
                if (distance <= rangeMax)
                {
                    if (distance >= rangeMin)
                    {
                        if (!nodes.Contains(current)) nodes.Add(current);
                    }
                    SearchAttack(current.N, rangeMin, rangeMax, distance + 1, nodes);
                    SearchAttack(current.S, rangeMin, rangeMax, distance + 1, nodes);
                    SearchAttack(current.E, rangeMin, rangeMax, distance + 1, nodes);
                    SearchAttack(current.W, rangeMin, rangeMax, distance + 1, nodes);
                } 
            }

            public List<MapNode> SearchMove(UnitStatus unit, int movement)
            {
                List<MapNode> nodes = new List<MapNode>();
                nodes.Add(this);
                SearchMove(unit, N, movement, nodes);
                SearchMove(unit, S, movement, nodes);
                SearchMove(unit, E, movement, nodes);
                SearchMove(unit, W, movement, nodes);
                return nodes;
            }
            private void SearchMove(UnitStatus unit, MapNode current, int movement, List<MapNode> nodes)
            {
                if (current == null) return;
                if (movement > current.tile.GetMoveConsumption(unit.unit))
                {
                    if (current.unit != null)
                    {
                        if (!map.GetUnitOwner(current.unit).IsAlly(map.GetUnitOwner(unit)))
                        {
                            return;

                        }
                    }
                    if (!nodes.Contains(current)) nodes.Add(current);                    
                    movement -= current.tile.GetMoveConsumption(unit.unit);
                    SearchMove(unit, current.N, movement, nodes);
                    SearchMove(unit, current.E, movement, nodes);
                    SearchMove(unit, current.S, movement, nodes);
                    SearchMove(unit, current.W, movement, nodes);
                }
            }

        }
    }
}
